<script>
import draggable from 'vuedraggable'
import render from '@/components/render/render'

/**
 * components 对象
    1. 提供表单项的操作按钮（复制和删除）。
    2. 定义方法 itemBtns，生成包含两个操作按钮的 JSX：
    复制：通过 copyItem 事件调用父组件的方法复制当前项。
    删除：通过 deleteItem 事件调用父组件的方法删除当前项。
 */
const components = {
	itemBtns(h, currentItem, index, list) {
		const { copyItem, deleteItem } = this.$listeners
		return [
			<span
				class="drawing-item-copy"
				title="复制"
				onClick={event => {
					copyItem(currentItem, list)
					event.stopPropagation()
				}}
			>
				<i class="el-icon-copy-document" />
			</span>,
			<span
				class="drawing-item-delete"
				title="删除"
				onClick={event => {
					deleteItem(index, list)
					event.stopPropagation()
				}}
			>
				<i class="el-icon-delete" />
			</span>,
		]
	},
}

/**
 * layouts 对象
    layouts 是核心逻辑，定义了三种布局的渲染规则：

    colFormItem：

    渲染单个列布局。
    包含 el-form-item 元素，用于设置标签和必填校验。
    显示复制和删除按钮。
    根据状态动态添加 active-from-item 和 unfocus-bordered 的样式。
    调用 render 组件用于渲染具体的子内容。
    rowFormItem：

    渲染一行布局，可以包含多个列。
    如果当前类型为 flex，会渲染一个弹性盒子布局。
    子组件通过 vuedraggable 实现拖拽排序。
    显示复制和删除按钮。
    raw：

    渲染原始组件。
    调用 render 组件，直接渲染配置定义的子内容
 */
const layouts = {
	colFormItem(h, currentItem, index, list) {
		const { activeItem } = this.$listeners
		const config = currentItem.__config__
		const child = renderChildren.apply(this, arguments)
		let className = this.activeId === config.formId ? 'drawing-item active-from-item' : 'drawing-item'
		if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
		let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
		if (config.showLabel === false) labelWidth = '0'
		return (
			<el-col
				span={config.span}
				class={className}
				nativeOnClick={event => {
					activeItem(currentItem)
					event.stopPropagation()
				}}
			>
				<el-form-item
					label-width={labelWidth}
					label={config.showLabel ? config.label : ''}
					required={config.required}
				>
					<render
						key={config.renderKey}
						conf={currentItem}
						onInput={event => {
							this.$set(config, 'defaultValue', event)
						}}
					>
						{child}
					</render>
				</el-form-item>
				{components.itemBtns.apply(this, arguments)}
			</el-col>
		)
	},
	rowFormItem(h, currentItem, index, list) {
		const { activeItem } = this.$listeners
		const config = currentItem.__config__
		const className = this.activeId === config.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
		let child = renderChildren.apply(this, arguments)
		if (currentItem.type === 'flex') {
			child = (
				<el-row type={currentItem.type} justify={currentItem.justify} align={currentItem.align}>
					{child}
				</el-row>
			)
		}
		return (
			<el-col span={config.span}>
				<el-row
					gutter={config.gutter}
					class={className}
					nativeOnClick={event => {
						activeItem(currentItem)
						event.stopPropagation()
					}}
				>
					<span class="component-name">{config.componentName}</span>
					<draggable
						list={config.children || []}
						animation={340}
						group="componentsGroup"
						class="drag-wrapper"
					>
						{child}
					</draggable>
					{components.itemBtns.apply(this, arguments)}
				</el-row>
			</el-col>
		)
	},
	raw(h, currentItem, index, list) {
		const config = currentItem.__config__
		const child = renderChildren.apply(this, arguments)
		return (
			<render
				key={config.renderKey}
				conf={currentItem}
				onInput={event => {
					this.$set(config, 'defaultValue', event)
				}}
			>
				{child}
			</render>
		)
	},
}

/**
 *  renderChildren 函数
    递归渲染当前项的子组件：
    判断 config.children 是否为数组。
    遍历每个子项，根据其 layout 动态调用对应的布局渲染方法。
 */
function renderChildren(h, currentItem, index, list) {
	const config = currentItem.__config__
	if (!Array.isArray(config.children)) return null
	return config.children.map((el, i) => {
		const layout = layouts[el.__config__.layout]
		if (layout) {
			return layout.call(this, h, el, i, config.children)
		}
		return layoutIsNotFound.call(this)
	})
}

/**
 * layoutIsNotFound 函数
    当指定的 layout 不存在时抛出错误，提示未匹配的布局类型。
 */
function layoutIsNotFound() {
	throw new Error(`没有与${this.currentItem.__config__.layout}匹配的layout`)
}

export default {
	components: {
		render,
		draggable,
	},
	/**
   *  currentItem：当前表单项的配置对象，包含元数据信息。
      index：当前项在列表中的索引。
      drawingList：当前所有表单项的列表，用于操作和渲染。
      activeId：当前激活的表单项  ID，用于设置激活样式。
      formConf：表单的全局配置（如未聚焦边框的样式）。
   */
	props: ['currentItem', 'index', 'drawingList', 'activeId', 'formConf'],
	/**
   * 核心渲染逻辑：
      根据当前项的 __config__.layout 动态调用对应的布局渲染方法。
      如果布局不存在，调用 layoutIsNotFound 报错。
   */
	render(h) {
		const layout = layouts[this.currentItem.__config__.layout]

		if (layout) {
			return layout.call(this, h, this.currentItem, this.index, this.drawingList)
		}
		return layoutIsNotFound.call(this)
	},
}
</script>
